EF object relational mapping met code
- We moeten referenties in ons domeinmodel toevoegen naamruimten en assemblies waarin de attributen worden gedefinieerd. Deze vervuiling heet 'domain vervuiling'.
- We kunnen dingen niet dynamisch veranderen; attributen worden statisch en kunnen niet worden overschreven.
- Er is geen centrale locatie waar we onze eigen conventies kunnen afdwingen.
Entity Framework Code First biedt een extra mapping API waarmee je die beperkingen kan overkomen: code mapping of fluent mapping. Alle functionaliteit van de attribuut-gebaseerde mapping is aanwezig en nog veel meer. We laten zien hoe je de meest voorkomende scenario's met code mapping kan implemeteren.
Fluent, of code, mapping wordt ingesteld op een instantie van de DbModelBuilder
klasse. De plaats waar we kunnen toegang krijgen tot een DbModelBuilder instantie is in de OnModelCreating
methode van de DbContext
.
public class ProjectsContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { //configuration goes here base.OnModelCreating(modelBuilder); } }
Deze infrastructuur methode wordt aangeroepen door Entity Framework wanneer het een context initialiseert. En dat nadat het automatisch alle entiteit-klassen waarnaar verwezen wordt in die context als DbSet
Schema
Voorbeelden van entiteitsmapping met behulp van code:
//set the table and schema modelBuilder.Entity().ToTable("Curstomer", "dbo"); //ignoring an entity and all properties of its type modelBuilder.Ignore ();
Hierboven zie je een voorbeeld van mapping van individuele eigenschappen. Maar de API laat het aaneenschakelen (chaining) van meerdere calls toe. Hier zie je hoe je tegelijkertijd de naam kolom, type, de maximale lengte, en het required attribuut kan instellen. Dit maakt de code leesbaarder.
//ignore a property modelBuilder.Entity().Ignore(x => x.FullName); //set a property’s values (column name, type, length, nullability) modelBuilder.Entity ().Property(x => x.FirstName). HasColumnName("FirstName"). HasColumnType("NVARCHAR"). HasMaxLength(50).IsRequired();
Primaire sleutels
Primary keys kan je als volgt creëren en genereren:
//setting a property as the key modelBuilder.Entity<Curstomer>().HasKey(x => x.ProjectId); //and the primary key generation strategy modelBuilder.Entity<Curstomer>().Property(x => x.CustomerId) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); //composite keys modelBuilder.Entity<Curstomer>().HasKey(x => new { x.FirstName, x.LastName, x.BirthDay });
Vreemde sleutels
Navigatie eigenschappen - de naam voor foreign keys in EFCF jargon - maak je als volgt:
//a bidirectional many-to-one and its inverse with cascade modelBuilder.Entity<Project>().HasRequired(x => x.Customer). WithMany(x => x.Projects).WillCascadeOnDelete(true); //a bidirectional one-to-many modelBuilder.Entity<Customer>().HasMany(x => x.Projects) . WithRequired(x => x.Customer); //a bidirectional many-to-many modelBuilder.Entity<Technology>().HasMany(x => x.Resources) . WithMany(x => x.Technologies); //a bidirectional one-to-one-or-zero with cascade modelBuilder.Entity<Project>().HasOptional(x => x.Detail) . WithRequired(x => x.Project).WillCascadeOnDelete(true); //a bidirectional one-to-one (both sides required) with cascade modelBuilder.Entity<Project>().HasRequired(x => x.Detail) . WithRequiredPrincipal(x => x.Project).WillCascadeOnDelete(true); //a bidirectional one-to-many with a foreign key property (CustomerId) modelBuilder.Entity<Project>().HasRequired(x => x.Customer). WithMany(x => x.Projects) .HasForeignKey(x => x.CustomerId); //a bidirectional one-to-many with a non-conventional foreign key column modelBuilder.Entity<Project>().HasRequired(x => x.Customer). WithMany(x => x.Projects) .Map(x => x.MapKey("FK_Customer_Id"));
Berekende kolommen
Een eenvoudige kolom die wordt gegenereerd in de database door een formule, in plaats van fysiek opgeslagen:
modelBuilder.Entity<Customer>().Property(x => x.FullName). HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
Een eigen configuratie klasse
De OnModelCreating
methode kan behoorlijk complex worden. Het EFCF biedt dan ook de mogelijkheid om configuraties te groeperen in eigen klasse. Deze klasse moet overerven van EntityTypeConfiguration <T>, Hier is een voorbeeld:
modelBuilder.Configurations.Add(new CustomerConfiguration()); public class CustomerConfiguration : EntityTypeConfiguration<Customer> { public CustomerConfiguration() { this.Table("FK_Customer_Id", "dbo"); this.Property(x => x.Name).HasMaxLength(50).IsRequired(); } }